Fix e2e on 11.12#560
Open
YogendraShelke wants to merge 9 commits into
Open
Conversation
YogendraShelke
force-pushed
the
update-screenshot-11.12
branch
2 times, most recently
from
July 24, 2026 11:46
6eed515 to
b6be27f
Compare
YogendraShelke
force-pushed
the
update-screenshot-11.12
branch
from
July 27, 2026 12:14
c9a59ea to
1ac6b5e
Compare
YogendraShelke
force-pushed
the
update-screenshot-11.12
branch
from
July 27, 2026 12:14
1ac6b5e to
eda1e26
Compare
chore: fix tests chore: update ios test timeout chore: inrease maestro driver setup timeout chore: address flaky tests chore: fix tests chore: revert chore: revert
…et index Flows navigate the Widgets menu by tapping a single letter, which filters and re-renders the list, then immediately tap the widget name. Nothing waited for that render, so the second tap raced it. Maestro's implicit element lookup usually absorbed the gap, but on a loaded CI runner it did not: Tap on "B"... COMPLETED Tap on "Bottom Sheet"... FAILED Element not found: Text matching regex: Bottom Sheet which then passed on retry with the same build. Three bottom-sheet flows hit this in one run. Insert an extendedWaitUntil on the widget name between the two taps, matching the pattern Modal_basic_non_native.yaml already used for its "Open" button. 71 flows across 20 widgets carried the race; all are now guarded. Verified: all 82 flow files still parse, all 71 index-taps are followed by a wait, and no flow ended up with a duplicated consecutive wait. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
restart_simulator is the recovery path for a wedged Maestro/XCTest driver
("iOS driver not ready in time"), but it did not restart anything. It ran
`simctl shutdown all || true`, discarding the result, and prepare_ios.sh then
reported:
Monitoring boot status for iPhone 17 Pro (...).
Device already booted, nothing to do.
The device never went down, so the shard got an app reinstall on top of the
same wedged runtime and ran degraded from that point on. Seen in a run where
the smoke check lost its driver and a later assertion then timed out.
Changes:
- Kill the XCTest runner before shutting down, not after: while it holds the
device, shutdown can fail.
- Target SIMULATOR_DEVICE_ID when known, falling back to `all`.
- Poll until the device reports Shutdown (bounded at 30s) and emit a
::warning:: if it never does, instead of silently continuing.
- Drop the blind `sleep 10`. Targeted `simctl shutdown <udid>` is synchronous
(measured ~3s to reach Shutdown), so the sleep only padded every retry.
Verified against a real simulator: booted device reaches Shutdown in ~3.4s
(was ~13s); an already-shutdown device logs the benign CoreSimulator 405 and
continues; the unset-UDID path falls back to `all`. Both return exit 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…creenshots
20 flows waited before takeScreenshot by watching for text that by design never
appears, with optional: true:
- extendedWaitUntil:
visible: randText # Any random text that does not exist in the UI
optional: true
timeout: 15000
That is a sleep, not a wait. It ALWAYS burns the full timeout (it can never
succeed early) and never confirms the UI settled, so it is both slow and flaky.
It cost 325s (5.4 min) per full run PER PLATFORM, and still was not enough: a
bottom-sheet screenshot came in at 14.7% similarity against a 95% threshold
because the sheet was mid-expand when captured, then passed on retry.
Replace with waitForAnimationToEnd, which polls until the screen stops changing
-- returning as soon as the image decode / sheet animation finishes, and still
capping at the timeout. Already used by animation-native, so no new concept.
Each site keeps its existing timeout as the cap, so no flow gets a smaller
budget than before; the saving comes from returning early rather than from
lowering the ceiling.
Verified: no randText remains anywhere, all 82 flow files parse, every
waitForAnimationToEnd has a timeout, all 20 timeouts carried over unchanged,
and the assertVisible count is unchanged (99) so no real assertion was dropped
along with the stale comments.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
NativePipeline already had concurrency + cancel-in-progress, but Build, UnitTests, Release and ShaCheck had none — so every push to a PR left the previous run of each still going. On GitHub Free all of them share one 20-concurrent-job cap with NativePipeline's ~10 test shards, so stale runs were not just noise: they delayed the run for the commit under review. cancel-in-progress is gated on pull_request. A push run on main / mx-* is the recorded CI result for that commit (and Release.yml's push path publishes), so those are allowed to finish; only superseded PR runs get cancelled. Not added to MarketplaceRelease.yml (tag-triggered publish — never cancel), NightlyDispatcher.yml (scheduled), the workflow_dispatch-only workflows, or PullRequestLabeler.yml (seconds long). fix: make native tests cancellable ci: make cancelling the native pipeline actually stop it Clicking "Cancel workflow" appeared to do nothing for minutes. The reason is that `if: always()` is exempt from cancellation by design: a step or job with always() keeps running (and a job with it can even start) after the run is cancelled. The pipeline used always() in eleven places, including every upload inside archive-test-results — so on cancel each of the ~10 in-flight shards first uploaded five artifact sets nobody was waiting for. Replaced all of them with `!cancelled()`, which is equivalent for the cases we care about — it is true on success AND on failure, so failing shards still archive their screenshots/logs/videos/diffs, and jobs with skipped dependencies still run — but is false on cancellation. A shard that trips timeout-minutes is not "cancelled" in this sense, so timeout artifacts survive. Not fixed here: the maestro bash harness does not trap SIGINT/SIGTERM, so a shard mid-flow still runs to the runner's force-kill. Cancellation is much faster, not instant.
YogendraShelke
force-pushed
the
update-screenshot-11.12
branch
from
July 27, 2026 12:47
062e66f to
238a920
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes three defects in IntroScreen's slide-position handling, all rooted in how SwipeableContainer reconciled activeIndex (React state) with the FlashList's real scroll offset. The previous code used an isInitializing flag flipped by a double requestAnimationFrame, which guessed at timing instead of tracking what was actually requested.
Problems Fixed
Problem 1
Reopening a page showed slide 1 instead of the slide in the Active slide attribute, and fired a spurious On slide change back to slide 1
Root cause
activeIndex initialized to 0 while initialScrollIndex rendered the attribute's slide, so state and screen disagreed on mount. The effect only re-scrolled when slide !== activeIndex, so a matching-but-wrong state was never
Fix
Seed activeIndex from the attribute via a useState initializer, and force the positioning scroll once on the first pass where width is known (hasAppliedInitialScroll), independent of whether activeIndex already matches
Problem 2
The initial slide was reached with an animation, briefly leaving slide content unreachable for TalkBack/VoiceOver
Root cause
goToSlide always animated. activeIndex applies immediately and drives accessibilityElementsHidden / importantForAccessibility, so the slide exposed to screen readers was off-screen until the animation landed
Fix
goToSlide(pageNum, animated = true); the initial jump passes animated: false
Problem 3
Using Next / Previous / pagination could snap back to slide 1 and report an extra slide change
Root cause
onMomentumScrollEnd fires for programmatic scrolls too, reporting the offset the list is leaving rather than the one it's heading to. That stale offset overwrote activeIndex and re-fired onSlideChange. A drag flag alone can't disambiguate: it's only cleared inside onMomentumScrollEnd, so a drag that produces no momentum event leaves it stuck true, and the next programmatic scroll's stale event is misread as a user swipe
Fix
Track pendingScrollTarget — the slide goToSlide actually requested. onMomentumScrollEnd ignores any event whose index disagrees with that target, clearing it once reached. onScrollBeginDrag clears the target so a user taking over is always honoured, which also prevents the target latching when a scroll emits no momentum event